#include "tffmpegvideoplaythread.h"
#include <QDebug>
#include <QImage>

TFFmpegVideoPlayThread::TFFmpegVideoPlayThread(QObject *parent) : QThread(parent)
{

}

TFFmpegVideoPlayThread::~TFFmpegVideoPlayThread()
{

}

/*
 * 开始播放
 */
void TFFmpegVideoPlayThread::startPlay()
{
    if(!isRunning()) {
        m_stopped = false;
        start();
    }
}

/*
 * 停止播放
 */
void TFFmpegVideoPlayThread::stopPlay()
{
    if(isRunning()) {
        m_stopped = true;
        quit();
        wait();
    }
}

/*
 * 初始化视频
 * nfmtctx   : 格式封装
 * nvideoidx : 视频序号
 * 返回值     : true:成功 false:失败
 */
bool TFFmpegVideoPlayThread::initVideo()
{
    int ret = 0;
    //获取视频流
    m_ffcustomPlayer.video_stream_idx = av_find_best_stream(m_ffcustomPlayer.format_ctx,AVMEDIA_TYPE_VIDEO,-1,-1,nullptr,0);
    if(m_ffcustomPlayer.video_stream_idx < 0) {
        qDebug() << "find video stream index error";
    }
    else {
        AVStream *videostream = m_ffcustomPlayer.format_ctx->streams[m_ffcustomPlayer.video_stream_idx];
        //打开解码器
        m_videoCtx = avcodec_alloc_context3(nullptr);
        ret = avcodec_parameters_to_context(m_videoCtx,videostream->codecpar);
        if(ret < 0) {
            qDebug() << "fail avcodec context";
            return false;
        }
        m_videoCodec = avcodec_find_decoder(m_videoCtx->codec_id);
        if(!m_videoCodec) {
            qDebug() << "video decoder not found" << m_videoCodec;
            return false;
        }
        //设置加速解码
//        m_videoCtx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
//        m_videoCtx->flags |= AV_CODEC_FLAG_LOW_DELAY;
//        m_videoCtx->flags2 |= AV_CODEC_FLAG2_FAST;
        //打开视频解码器
        int nret = avcodec_open2(m_videoCtx,m_videoCodec,nullptr);
        if(nret < 0) {
            qDebug() << "open video codec error";
            return false;
        }

        m_videoWidth = m_videoCtx->width;
        m_videoHeight = m_videoCtx->height;
        //分配视频数据内存
        int nbytesize = av_image_get_buffer_size(AV_PIX_FMT_RGB32,m_videoWidth,m_videoHeight,1);
        m_videoData = reinterpret_cast<uint8_t*>(av_malloc(size_t(nbytesize) * sizeof (uint8_t)));
        if(!m_videoData) {
            av_free(m_videoData);
            return false;
        }
        //分配 视频帧 目标视频帧 视频帧格式->目标视频帧格式
        m_videoFrameDst = av_frame_alloc();
        m_videoFrame = av_frame_alloc();
        //定义像素格式
        AVPixelFormat ndstformat = AV_PIX_FMT_RGB32;
        //设置解码参数
        int nflags = SWS_FAST_BILINEAR;
        //开辟缓存存储一帧数据
        av_image_fill_arrays(m_videoFrameDst->data,m_videoFrameDst->linesize,m_videoData,ndstformat,m_videoWidth,m_videoHeight,1);
        //图像转换
        m_videoSwsCtx = sws_getContext(m_videoWidth,m_videoHeight,m_videoCtx->pix_fmt,m_videoWidth,m_videoHeight,ndstformat,nflags,nullptr,nullptr,nullptr);
    }
    return true;
}

/*
 * 设置解码开始时间
 * m_startTime : 解码开始时间
 */
void TFFmpegVideoPlayThread::setStartTime(int64_t nstarttime)
{
    m_startTime = nstarttime;
}

/*
 * 设置时间基准
 * ntimebase : 时间基准
 */
void TFFmpegVideoPlayThread::setTimeBase(AVRational ntimebase)
{
    m_timeBase = ntimebase;
}

/*
 * 解码视频
 * npacket : 视频包
 */
void TFFmpegVideoPlayThread::decodeVideo(AVPacket *npacket)
{
    int nframefinish = avcodec_send_packet(m_videoCtx,npacket);
    if(nframefinish >= 0) {
        nframefinish = avcodec_receive_frame(m_videoCtx,m_videoFrame);
        //解码成功
        if(nframefinish >= 0) {
            decodeImage();
        }
        //解码失败
        else {
            //no action
        }
    }
}

/*
 * 解码图像
 */
void TFFmpegVideoPlayThread::decodeImage()
{
    int nret = sws_scale(m_videoSwsCtx,m_videoFrame->data,m_videoFrame->linesize,0,
                         m_videoHeight,m_videoFrameDst->data,m_videoFrameDst->linesize);
    if(nret >= 0) {
        QImage nimage(m_videoWidth,m_videoHeight,QImage::Format_RGB32);
        memcpy(nimage.bits(),m_videoData,nimage.sizeInBytes());
        emit sigGetVideoFrame(nimage);
    }
}

/*
 * 运行
 */
void TFFmpegVideoPlayThread::run()
{
    AVStream *st = m_ffcustomPlayer.format_ctx->streams[m_ffcustomPlayer.video_stream_idx];
    AVRational frame_rate = av_guess_frame_rate(m_ffcustomPlayer.format_ctx, st, NULL);
    //帧间隔就是 FPS 的倒数
    double duration = av_q2d((AVRational){frame_rate.den, frame_rate.num});
    duration = isnan(duration) ? 0.040 : duration;
    double start_time, now_time,diff_time,remaining_time;

    while (!m_stopped) {
        if(!m_ffcustomPlayer.videopktList.isEmpty()) {
            AVPacket *pvideopkt = m_ffcustomPlayer.popVideoFront();

            start_time = av_gettime_relative() / 1000000.0;
            decodeVideo(pvideopkt);

            m_ffcustomPlayer.video_clock += duration;
            if (m_videoFrame->pts == AV_NOPTS_VALUE)
                m_ffcustomPlayer.video_pts = m_ffcustomPlayer.video_clock;
            else
                m_ffcustomPlayer.video_pts = m_videoFrame->pts * av_q2d(m_timeBase);
            diff_time = (m_ffcustomPlayer.audio_pts > 0) ? (m_ffcustomPlayer.video_pts - m_ffcustomPlayer.audio_pts) : 0;

            now_time = av_gettime_relative() / 1000000.0;
            if(fabs(diff_time) > 5*duration) {
                if(diff_time > 0) {
                    remaining_time = 2*duration;
                }
                else  {
                    remaining_time = FFMAX(0.01+start_time-now_time,0);
                }
            }
            else {
                if(fabs(diff_time) < duration) {
                    remaining_time = FFMAX(duration+start_time-now_time,0);
                }
            }
            av_usleep((unsigned long)(remaining_time * 1000000.0));

//            TFFmpegSupporter::delayTime(m_timeBase,pvideopkt,m_startTime);
        }
        else {
            QThread::msleep(100);
        }
    }
}
